//
//  CropView.m
//  OpenGLGame
//
//  Created by Nguyen Cong Huy on 5/2/13.
//  Copyright (c) 2013 UIT. All rights reserved.
//

#import "CropView.h"

#define NOT_IN_CROP_ALPHA 0.5f
#define EXTEND_BUTTON_AREA  50          // button extend outside for touch easier

@interface CropView(){
    
}

- (CGRect) rotateNormalizeRect:(CGRect)rect step:(int)step;

@end

@implementation CropView

@synthesize minCropSize;
@synthesize cropRect;
@synthesize imageRect;
@synthesize scale;
@synthesize isEnableCrop;
@synthesize ratio;
@synthesize delegate;

- (id)initWithFrame:(CGRect)frame padding:(float)_padding cropRatio:(float)_ratio topBottomArrowImage:(UIImage*)topBottomImage leftRightArrowImage:(UIImage*) leftRightImage arrowSize:(float)arrowSize;
{
    self = [super initWithFrame:frame];
    if (self) {
        self.backgroundColor = [UIColor blackColor];
        padding = _padding;
        self.userInteractionEnabled = YES;
        
        imageView = [[UIImageView alloc] initWithFrame:CGRectMake(self.frame.origin.x + padding, self.frame.origin.y + padding, self.frame.size.width - 2*padding, self.frame.size.height - 2*padding)];
        
        imageView.contentMode = UIViewContentModeScaleAspectFit;
        imageView.userInteractionEnabled = false;
        [self addSubview:imageView];
        
        self.minCropSize = CGSizeMake(0, 0);
        
        
        // view to opaque border area
        topView = [[UIView alloc] init];
        topView.backgroundColor = [UIColor colorWithRed:0.0f green:0.0f blue:0.0f alpha:NOT_IN_CROP_ALPHA];
        [imageView addSubview:topView];
        
        bottomView = [[UIView alloc] init];
        bottomView.backgroundColor = [UIColor colorWithRed:0.0f green:0.0f blue:0.0f alpha:NOT_IN_CROP_ALPHA];
        [imageView addSubview:bottomView];
        
        leftView = [[UIView alloc] init];
        leftView.backgroundColor = [UIColor colorWithRed:0.0f green:0.0f blue:0.0f alpha:NOT_IN_CROP_ALPHA];
        [imageView addSubview:leftView];
        
        rightView = [[UIView alloc] init];
        rightView.backgroundColor = [UIColor colorWithRed:0.0f green:0.0f blue:0.0f alpha:NOT_IN_CROP_ALPHA];
        [imageView addSubview:rightView];
        
        cropView = [[UIView alloc] init];
        cropView.backgroundColor = [UIColor clearColor];
        cropView.layer.borderColor = [UIColor colorWithRed:0.019 green:0.713 blue:0.969 alpha:1.0].CGColor;
        cropView.layer.borderWidth = 1;
        cropView.userInteractionEnabled = true;
        [imageView addSubview: cropView];
        
        topArrow = [[UIImageView alloc] initWithImage:topBottomImage];
        topArrow.frame = CGRectMake(0, 0, arrowSize, arrowSize);
        topArrow.userInteractionEnabled = true;
        topArrow.hidden = true;
        topArrow.contentMode = UIViewContentModeCenter;
        [imageView addSubview:topArrow];
        
        bottomArrow = [[UIImageView alloc] initWithImage:topBottomImage];
        bottomArrow.frame = CGRectMake(0, 0, arrowSize, arrowSize);
        bottomArrow.userInteractionEnabled = true;
        bottomArrow.hidden = true;
        bottomArrow.contentMode = UIViewContentModeCenter;
        [imageView addSubview:bottomArrow];
        
        leftArrow = [[UIImageView alloc] initWithImage:leftRightImage];
        leftArrow.frame = CGRectMake(0, 0, arrowSize, arrowSize);
        leftArrow.userInteractionEnabled = true;
        leftArrow.hidden = true;
        leftArrow.contentMode = UIViewContentModeCenter;
        [imageView addSubview:leftArrow];
        
        rightArrow = [[UIImageView alloc] initWithImage:leftRightImage];
        rightArrow.frame = CGRectMake(0, 0, arrowSize, arrowSize);
        rightArrow.userInteractionEnabled = true;
        rightArrow.hidden = true;
        rightArrow.contentMode = UIViewContentModeCenter;
        [imageView addSubview:rightArrow];
        
        UIPanGestureRecognizer *gesture =  [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panTapEvent:)];
        [self addGestureRecognizer:gesture];
        self.isEnableCrop = true;
        
        ratio = _ratio;
        
    }
    return self;
}

-(void)dealloc{ 
    [topArrow release];
    [leftArrow release];
    [bottomArrow release];
    [rightArrow release];
    
    [cropView release];
    [topView release];
    [leftView release];
    [bottomView release];
    [rightView release];
    [imageView release];
    
    [delegate release];
    
    [super dealloc];
}

- (void)setImage:(UIImage *)image{
    [imageView setImage:image];
    
    float widthScale = imageView.frame.size.width / imageView.image.size.width;
    float heightScale = imageView.frame.size.height / imageView.image.size.height;
    scale = MIN(widthScale, heightScale);
    
    
    // calculate imageRect
    float imageRectWidth = imageView.image.size.width*scale;
    float imageRectHeight = imageView.image.size.height*scale;
    imageRect = CGRectMake((imageView.frame.size.width - imageRectWidth)/2,
                           (imageView.frame.size.height - imageRectHeight)/2,
                           imageRectWidth,
                           imageRectHeight);
    self.ratio = ratio;
    self.isEnableCrop = isEnableCrop;
}

- (UIImage*) image{
    return imageView.image;
}

- (void)setRatio:(float)_ratio{
    ratio = _ratio;
}

- (CGRect) cropRectWhenCropEnable{
    if(ratio != -1){
        float cropViewRectWidth = imageView.image.size.width*scale;                  // width of crop rect is width of image in image view
        float  cropViewRectHeight = cropViewRectWidth/ratio;
        float cropViewX, cropViewY;
        
        if(cropViewRectHeight > imageView.image.size.height*scale){                // horizontal
            cropViewRectHeight = imageView.image.size.height*scale;
            cropViewRectWidth = cropViewRectHeight * ratio;
        }
        
        cropViewX = (imageView.frame.size.width - cropViewRectWidth)/2;
        cropViewY = (imageView.frame.size.height - cropViewRectHeight)/2;
        
        // set crop rect
        return CGRectMake(cropViewX, cropViewY, cropViewRectWidth, cropViewRectHeight);
    }
    else{
        return imageRect;
    }
}


- (void) panTapEvent:(UIPanGestureRecognizer *)recognizer {
    
    CGPoint pointInImageView = [recognizer locationInView:imageView];
    
    CGPoint translatedPoint = [recognizer translationInView:self];
    
    static CGPoint oldLocation;
    oldCropRect = cropRect;
    
    if([recognizer state] == UIGestureRecognizerStateBegan) {
        oldLocation = translatedPoint;
        
        if(CGRectContainsPoint(topArrow.frame, pointInImageView))
            view = topArrow;
        else if(CGRectContainsPoint(bottomArrow.frame, pointInImageView))
            view = bottomArrow;
        else if(CGRectContainsPoint(leftArrow.frame, pointInImageView))
            view = leftArrow;
        else if(CGRectContainsPoint(rightArrow.frame, pointInImageView))
            view = rightArrow;
        else if(CGRectContainsPoint(cropView.frame, pointInImageView))
            view = cropView;
    }
    
    else if([recognizer state] == UIGestureRecognizerStateChanged) {
        float deltaY = translatedPoint.y - oldLocation.y;
        float deltaX = translatedPoint.x - oldLocation.x;
        
        if(ratio > 0){
            if(view == topArrow){
                cropRect.origin.y += deltaY;
                cropRect.size.height -= deltaY*2;
                
                float newDeltaX = deltaY*ratio;
                cropRect.size.width -= newDeltaX*2;
                cropRect.origin.x += newDeltaX;
            }
            else if(view == bottomArrow){
                cropRect.origin.y -= deltaY;
                cropRect.size.height += deltaY*2;
                
                float newDeltaX = deltaY*ratio;
                cropRect.size.width += newDeltaX*2;
                cropRect.origin.x -= newDeltaX;
            }
            else if(view == leftArrow){
                cropRect.origin.x += deltaX;
                cropRect.size.width -= deltaX*2;
                
                float newDeltaY = deltaX/ratio;
                cropRect.size.height -= newDeltaY*2;
                cropRect.origin.y += newDeltaY;
            }
            else if(view == rightArrow){
                cropRect.origin.x -= deltaX;
                cropRect.size.width += deltaX*2;
                
                float newDeltaY = deltaX/ratio;
                cropRect.size.height += newDeltaY*2;
                cropRect.origin.y -= newDeltaY;
            }
            
            //check min size
            if (cropRect.size.width < minCropSize.width){
                float deltaX = minCropSize.width - cropRect.size.width;
                float deltaY = deltaX/ratio;
                
                cropRect.size.width = minCropSize.width;
                cropRect.size.height = cropRect.size.width/ratio;
                
                cropRect.origin.x -= deltaX/2;
                cropRect.origin.y -= deltaY/2;
            }
            if(cropRect.size.height < minCropSize.height){
                float deltaY = minCropSize.height - cropRect.size.height;
                float deltaX = deltaY*ratio;
                
                cropRect.size.height = minCropSize.height;
                cropRect.size.width = cropRect.size.height*ratio;
                
                cropRect.origin.x -= deltaX/2;
                cropRect.origin.y -= deltaY/2;
            }
            
            // check crop rect in image bound
            if (cropRect.size.width > imageRect.size.width){
                float deltaX = imageRect.size.width - cropRect.size.width;
                float deltaY = deltaX/ratio;
                
                cropRect.size.width = imageRect.size.width;
                cropRect.size.height = cropRect.size.width/ratio;
                
                cropRect.origin.x -= deltaX/2;
                cropRect.origin.y -= deltaY/2;
            }
            
            if(cropRect.size.height > imageRect.size.height){
                float deltaY = imageRect.size.height - cropRect.size.height;
                float deltaX = deltaY*ratio;
                
                cropRect.size.height = imageRect.size.height;
                cropRect.size.width = cropRect.size.height*ratio;
                
                cropRect.origin.x -= deltaX/2;
                cropRect.origin.y -= deltaY/2;
            }
            
        }
        
        // ratio < 0, crop not square
        else{
            deltaX *= 1.2f;
            deltaY *= 1.2f;
            if(view == topArrow){
                cropRect.origin.y += deltaY;
                cropRect.size.height -= deltaY;
            }
            else if(view == bottomArrow){
                cropRect.size.height += deltaY;
            }
            else if(view == leftArrow){
                cropRect.origin.x += deltaX;
                cropRect.size.width -= deltaX;
            }
            else if(view == rightArrow){
                cropRect.size.width += deltaX;
            }
            
            //check min size
            if (cropRect.size.width < minCropSize.width){
                float deltaX = minCropSize.width - cropRect.size.width;
                
                cropRect.size.width = minCropSize.width;
                
                if(view == leftArrow)
                    cropRect.origin.x -= deltaX;
            }
            if(cropRect.size.height < minCropSize.height){
                float deltaY = minCropSize.height - cropRect.size.height;
                
                cropRect.size.height = minCropSize.height;
                
                if(view == topArrow)
                    cropRect.origin.y -= deltaY;
            }
            
            // check crop rect in image bound
            if (cropRect.size.width > imageRect.size.width){
                float deltaX = imageRect.size.width - cropRect.size.width;
                
                cropRect.size.width = imageRect.size.width;
                
                cropRect.origin.x -= deltaX;
            }
            
            if(cropRect.size.height > imageRect.size.height){
                float deltaY = imageRect.size.height - cropRect.size.height;
                
                cropRect.size.height = imageRect.size.height;
                
                cropRect.origin.y -= deltaY;
            }
        }
        
        if(view == cropView){
            cropRect.origin.x = cropRect.origin.x + (translatedPoint.x - oldLocation.x);
            cropRect.origin.y = cropRect.origin.y + (translatedPoint.y - oldLocation.y);
        }
        
        
        
        CGRect bigRect = imageRect;
        if (cropRect.origin.x < bigRect.origin.x) {
            cropRect.origin.x = bigRect.origin.x;
        }
        if (cropRect.origin.x + cropRect.size.width > bigRect.origin.x + bigRect.size.width) {
            cropRect.origin.x = bigRect.origin.x + bigRect.size.width - cropRect.size.width;
        }
        
        if (cropRect.origin.y < bigRect.origin.y) {
            cropRect.origin.y = bigRect.origin.y;
        }
        if (cropRect.origin.y + cropRect.size.height > bigRect.origin.y + bigRect.size.height) {
            cropRect.origin.y = bigRect.origin.y + bigRect.size.height - cropRect.size.height;
        }
        
    }
    
    if(delegate && [delegate respondsToSelector:@selector(cropViewDidChangeCropSize:isFullImage:)]){
        if(abs(cropRect.size.width - imageRect.size.width) > 2
           || abs(cropRect.size.height - imageRect.size.height) > 2){
            
                [delegate cropViewDidChangeCropSize:self isFullImage:false];
        }
        else [delegate cropViewDidChangeCropSize:self isFullImage:true];
    }
    [self setCropFrame:cropRect];
    oldLocation = translatedPoint;
    
    if([recognizer state] == UIGestureRecognizerStateEnded) {
        view = nil;
    }
}

- (void) setCropFrame:(CGRect)cropFrame{
    cropView.frame = cropFrame;
    cropRect = cropFrame;
    
    CGRect arrowRect;
    
    arrowRect = topArrow.frame;
    arrowRect.origin.x = cropView.frame.origin.x + (cropView.frame.size.width - arrowRect.size.width)/2;
    arrowRect.origin.y = cropView.frame.origin.y - arrowRect.size.height/2;
    topArrow.frame = arrowRect;
    
    arrowRect = bottomArrow.frame;
    arrowRect.origin.x = cropView.frame.origin.x + (cropView.frame.size.width - arrowRect.size.width)/2;
    arrowRect.origin.y = cropView.frame.origin.y + cropView.frame.size.height - arrowRect.size.height/2;
    bottomArrow.frame = arrowRect;
    
    arrowRect = leftArrow.frame;
    arrowRect.origin.x = cropView.frame.origin.x - arrowRect.size.width/2;
    arrowRect.origin.y = cropView.frame.origin.y + (cropView.frame.size.height - arrowRect.size.height)/2;
    leftArrow.frame = arrowRect;
    
    arrowRect = rightArrow.frame;
    arrowRect.origin.x = cropView.frame.origin.x + cropView.frame.size.width - arrowRect.size.width/2;
    arrowRect.origin.y = cropView.frame.origin.y + (cropView.frame.size.height - arrowRect.size.height)/2;
    rightArrow.frame = arrowRect;
    
    topView.frame = CGRectMake(imageRect.origin.x, imageRect.origin.y, imageRect.size.width, cropView.frame.origin.y - imageRect.origin.y);
    bottomView.frame = CGRectMake(imageRect.origin.x, cropView.frame.origin.y + cropView.frame.size.height, imageRect.size.width, imageRect.origin.y + imageRect.size.height - (cropView.frame.origin.y + cropView.frame.size.height));
    leftView.frame = CGRectMake(imageRect.origin.x, topView.frame.origin.y + topView.frame.size.height, cropView.frame.origin.x - imageRect.origin.x, cropView.frame.size.height);
    rightView.frame = CGRectMake(cropView.frame.origin.x + cropView.frame.size.width, leftView.frame.origin.y, imageRect.origin.x + imageRect.size.width - (cropView.frame.origin.x + cropView.frame.size.width), leftView.frame.size.height);
    
}

- (CGRect)cropRect{
    return cropView.frame;
}

- (void)setIsEnableCrop:(bool)_isEnableCrop{
    isEnableCrop = _isEnableCrop;
    
    if(isEnableCrop == true){
        self.userInteractionEnabled = true;
        topArrow.hidden = false;
        leftArrow.hidden = false;
        bottomArrow.hidden = false;
        rightArrow.hidden = false;
    }
    else{
        self.userInteractionEnabled = false;
        topArrow.hidden = true;
        leftArrow.hidden = true;
        bottomArrow.hidden = true;
        rightArrow.hidden = true;
        oldCropRect = cropRect;
    }
}

- (void) updateView{
    if(isEnableCrop == true){
        [self setCropFrame:[self cropRectWhenCropEnable]];
    }
    else{
        [self setCropFrame:imageRect];
    }
}

- (CGRect) getNormalizeCropRect{
    return CGRectMake((cropRect.origin.x - imageRect.origin.x)/imageRect.size.width,
                                      (cropRect.origin.y - imageRect.origin.y)/imageRect.size.height,
                                      cropRect.size.width/imageRect.size.width,
                                      cropRect.size.height/imageRect.size.height);
}

- (void) setNormalizeCropRect:(CGRect)_cropRect withStep:(int)step{
    CGRect newRect = [self rotateNormalizeRect:_cropRect step:step];
    CGRect ccropRect = CGRectMake(imageRect.origin.x + newRect.origin.x * imageRect.size.width,
                                  imageRect.origin.y + newRect.origin.y * imageRect.size.height,
                                  newRect.size.width * imageRect.size.width,
                                  newRect.size.height * imageRect.size.height);
    [self setCropFrame:ccropRect];
}

- (CGRect) rotateNormalizeRect:(CGRect)rect step:(int)step{
    CGRect newRect;
    int newStep = step % 4;
    switch (newStep) {
        case 0:
            newRect = rect;
            break;
        case 1:
            newRect.origin.x = rect.origin.y;
            newRect.origin.y = 1 - rect.origin.x - rect.size.width;
            newRect.size.width = rect.size.height;
            newRect.size.height = rect.size.width;
            break;
        case 2:
            newRect.origin.x = 1 - rect.origin.x - rect.size.width;
            newRect.origin.y = 1 - rect.origin.y - rect.size.height;
            newRect.size.width = rect.size.width;
            newRect.size.height = rect.size.height;
            break;
        case 3:
            newRect.origin.x = 1 - rect.origin.y - rect.size.height;
            newRect.origin.y =  rect.origin.x;
            newRect.size.width = rect.size.height;
            newRect.size.height = rect.size.width;
            break;
    }
    return newRect;
}

@end
